package org.cy.evolution.ioc.compiler;

import com.google.auto.service.AutoService;

import org.cy.evolution.ioc.annotation.Component;
import org.cy.evolution.ioc.compiler.generator.ComponentGenerator;

import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

@AutoService(Processor.class)
public class ComponentProcessor extends AbstractProcessor {

    // 文件工具类
    private Filer filer;

    // 元素工具类
    private Elements elements;

    // 日志消息工具类
    private Messager messager;

    private Map<String, ComponentGenerator> componentGenerators = new HashMap<>(0);

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        this.filer = processingEnvironment.getFiler();
        this.elements = processingEnvironment.getElementUtils();
        this.messager = processingEnvironment.getMessager();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
        for (TypeElement annotation: annotations) {
            for (Element element : roundEnvironment.getElementsAnnotatedWith(annotation)){
                TypeElement classElement = (TypeElement) element;
                String fullName = classElement.getQualifiedName().toString();
                ComponentGenerator generator = componentGenerators.get(fullName);
                if (null == generator) {
                    generator = new ComponentGenerator(messager, elements, classElement);
                    componentGenerators.put(fullName, generator);
                }
            }
        }
        for (ComponentGenerator generator: componentGenerators.values()) {
            try {
                generator.generate().writeTo(this.filer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>(0);
        types.add(Component.class.getCanonicalName());
        return types;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}
